home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / python2.5 / tarfile.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-29  |  63KB  |  2,204 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.5)
  3.  
  4. '''Read from and write to tar format archives.
  5. '''
  6. __version__ = '$Revision: 60730 $'
  7. version = '0.8.0'
  8. __author__ = 'Lars Gust\xe4bel (lars@gustaebel.de)'
  9. __date__ = '$Date: 2008-02-11 19:36:07 +0100 (Mon, 11 Feb 2008) $'
  10. __cvsid__ = '$Id: tarfile.py 60730 2008-02-11 18:36:07Z lars.gustaebel $'
  11. __credits__ = 'Gustavo Niemeyer, Niels Gust\xe4bel, Richard Townsend.'
  12. import sys
  13. import os
  14. import shutil
  15. import stat
  16. import errno
  17. import time
  18. import struct
  19. import copy
  20. if sys.platform == 'mac':
  21.     raise ImportError, 'tarfile does not work for platform==mac'
  22.  
  23.  
  24. try:
  25.     import grp
  26.     import pwd
  27. except ImportError:
  28.     grp = pwd = None
  29.  
  30. __all__ = [
  31.     'TarFile',
  32.     'TarInfo',
  33.     'is_tarfile',
  34.     'TarError']
  35. NUL = '\x00'
  36. BLOCKSIZE = 512
  37. RECORDSIZE = BLOCKSIZE * 20
  38. MAGIC = 'ustar'
  39. VERSION = '00'
  40. LENGTH_NAME = 100
  41. LENGTH_LINK = 100
  42. LENGTH_PREFIX = 155
  43. MAXSIZE_MEMBER = 0x1FFFFFFFFL
  44. REGTYPE = '0'
  45. AREGTYPE = '\x00'
  46. LNKTYPE = '1'
  47. SYMTYPE = '2'
  48. CHRTYPE = '3'
  49. BLKTYPE = '4'
  50. DIRTYPE = '5'
  51. FIFOTYPE = '6'
  52. CONTTYPE = '7'
  53. GNUTYPE_LONGNAME = 'L'
  54. GNUTYPE_LONGLINK = 'K'
  55. GNUTYPE_SPARSE = 'S'
  56. SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, CONTTYPE, CHRTYPE, BLKTYPE, GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, GNUTYPE_SPARSE)
  57. REGULAR_TYPES = (REGTYPE, AREGTYPE, CONTTYPE, GNUTYPE_SPARSE)
  58. S_IFLNK = 40960
  59. S_IFREG = 32768
  60. S_IFBLK = 24576
  61. S_IFDIR = 16384
  62. S_IFCHR = 8192
  63. S_IFIFO = 4096
  64. TSUID = 2048
  65. TSGID = 1024
  66. TSVTX = 512
  67. TUREAD = 256
  68. TUWRITE = 128
  69. TUEXEC = 64
  70. TGREAD = 32
  71. TGWRITE = 16
  72. TGEXEC = 8
  73. TOREAD = 4
  74. TOWRITE = 2
  75. TOEXEC = 1
  76.  
  77. def stn(s, length):
  78.     '''Convert a python string to a null-terminated string buffer.
  79.     '''
  80.     return s[:length] + (length - len(s)) * NUL
  81.  
  82.  
  83. def nts(s):
  84.     '''Convert a null-terminated string field to a python string.
  85.     '''
  86.     p = s.find('\x00')
  87.     if p == -1:
  88.         return s
  89.     
  90.     return s[:p]
  91.  
  92.  
  93. def nti(s):
  94.     '''Convert a number field to a python number.
  95.     '''
  96.     if s[0] != chr(128):
  97.         if not nts(s):
  98.             pass
  99.         n = int('0', 8)
  100.     else:
  101.         n = 0x0L
  102.         for i in xrange(len(s) - 1):
  103.             n <<= 8
  104.             n += ord(s[i + 1])
  105.         
  106.     return n
  107.  
  108.  
  109. def itn(n, digits = 8, posix = False):
  110.     '''Convert a python number to a number field.
  111.     '''
  112.     if n <= n:
  113.         pass
  114.     elif n < 8 ** (digits - 1):
  115.         s = '%0*o' % (digits - 1, n) + NUL
  116.     elif posix:
  117.         raise ValueError('overflow in number field')
  118.     
  119.     if n < 0:
  120.         n = struct.unpack('L', struct.pack('l', n))[0]
  121.     
  122.     s = ''
  123.     for i in xrange(digits - 1):
  124.         s = chr(n & 255) + s
  125.         n >>= 8
  126.     
  127.     s = chr(128) + s
  128.     return s
  129.  
  130.  
  131. def calc_chksums(buf):
  132.     """Calculate the checksum for a member's header by summing up all
  133.        characters except for the chksum field which is treated as if
  134.        it was filled with spaces. According to the GNU tar sources,
  135.        some tars (Sun and NeXT) calculate chksum with signed char,
  136.        which will be different if there are chars in the buffer with
  137.        the high bit set. So we calculate two checksums, unsigned and
  138.        signed.
  139.     """
  140.     unsigned_chksum = 256 + sum(struct.unpack('148B', buf[:148]) + struct.unpack('356B', buf[156:512]))
  141.     signed_chksum = 256 + sum(struct.unpack('148b', buf[:148]) + struct.unpack('356b', buf[156:512]))
  142.     return (unsigned_chksum, signed_chksum)
  143.  
  144.  
  145. def copyfileobj(src, dst, length = None):
  146.     '''Copy length bytes from fileobj src to fileobj dst.
  147.        If length is None, copy the entire content.
  148.     '''
  149.     if length == 0:
  150.         return None
  151.     
  152.     if length is None:
  153.         shutil.copyfileobj(src, dst)
  154.         return None
  155.     
  156.     BUFSIZE = 16384
  157.     (blocks, remainder) = divmod(length, BUFSIZE)
  158.     for b in xrange(blocks):
  159.         buf = src.read(BUFSIZE)
  160.         if len(buf) < BUFSIZE:
  161.             raise IOError('end of file reached')
  162.         
  163.         dst.write(buf)
  164.     
  165.     if remainder != 0:
  166.         buf = src.read(remainder)
  167.         if len(buf) < remainder:
  168.             raise IOError('end of file reached')
  169.         
  170.         dst.write(buf)
  171.     
  172.  
  173. filemode_table = (((S_IFLNK, 'l'), (S_IFREG, '-'), (S_IFBLK, 'b'), (S_IFDIR, 'd'), (S_IFCHR, 'c'), (S_IFIFO, 'p')), ((TUREAD, 'r'),), ((TUWRITE, 'w'),), ((TUEXEC | TSUID, 's'), (TSUID, 'S'), (TUEXEC, 'x')), ((TGREAD, 'r'),), ((TGWRITE, 'w'),), ((TGEXEC | TSGID, 's'), (TSGID, 'S'), (TGEXEC, 'x')), ((TOREAD, 'r'),), ((TOWRITE, 'w'),), ((TOEXEC | TSVTX, 't'), (TSVTX, 'T'), (TOEXEC, 'x')))
  174.  
  175. def filemode(mode):
  176.     """Convert a file's mode to a string of the form
  177.        -rwxrwxrwx.
  178.        Used by TarFile.list()
  179.     """
  180.     perm = []
  181.     for table in filemode_table:
  182.         for bit, char in table:
  183.             if mode & bit == bit:
  184.                 perm.append(char)
  185.                 break
  186.                 continue
  187.         
  188.     
  189.     return ''.join(perm)
  190.  
  191. if os.sep != '/':
  192.     
  193.     normpath = lambda path: os.path.normpath(path).replace(os.sep, '/')
  194. else:
  195.     normpath = os.path.normpath
  196.  
  197. class TarError(Exception):
  198.     '''Base exception.'''
  199.     pass
  200.  
  201.  
  202. class ExtractError(TarError):
  203.     '''General exception for extract errors.'''
  204.     pass
  205.  
  206.  
  207. class ReadError(TarError):
  208.     '''Exception for unreadble tar archives.'''
  209.     pass
  210.  
  211.  
  212. class CompressionError(TarError):
  213.     '''Exception for unavailable compression methods.'''
  214.     pass
  215.  
  216.  
  217. class StreamError(TarError):
  218.     '''Exception for unsupported operations on stream-like TarFiles.'''
  219.     pass
  220.  
  221.  
  222. class _LowLevelFile:
  223.     '''Low-level file object. Supports reading and writing.
  224.        It is used instead of a regular file object for streaming
  225.        access.
  226.     '''
  227.     
  228.     def __init__(self, name, mode):
  229.         mode = {
  230.             'r': os.O_RDONLY,
  231.             'w': os.O_WRONLY | os.O_CREAT | os.O_TRUNC }[mode]
  232.         if hasattr(os, 'O_BINARY'):
  233.             mode |= os.O_BINARY
  234.         
  235.         self.fd = os.open(name, mode)
  236.  
  237.     
  238.     def close(self):
  239.         os.close(self.fd)
  240.  
  241.     
  242.     def read(self, size):
  243.         return os.read(self.fd, size)
  244.  
  245.     
  246.     def write(self, s):
  247.         os.write(self.fd, s)
  248.  
  249.  
  250.  
  251. class _Stream:
  252.     '''Class that serves as an adapter between TarFile and
  253.        a stream-like object.  The stream-like object only
  254.        needs to have a read() or write() method and is accessed
  255.        blockwise.  Use of gzip or bzip2 compression is possible.
  256.        A stream-like object could be for example: sys.stdin,
  257.        sys.stdout, a socket, a tape device etc.
  258.  
  259.        _Stream is intended to be used only internally.
  260.     '''
  261.     
  262.     def __init__(self, name, mode, comptype, fileobj, bufsize):
  263.         '''Construct a _Stream object.
  264.         '''
  265.         self._extfileobj = True
  266.         if fileobj is None:
  267.             fileobj = _LowLevelFile(name, mode)
  268.             self._extfileobj = False
  269.         
  270.         if comptype == '*':
  271.             fileobj = _StreamProxy(fileobj)
  272.             comptype = fileobj.getcomptype()
  273.         
  274.         if not name:
  275.             pass
  276.         self.name = ''
  277.         self.mode = mode
  278.         self.comptype = comptype
  279.         self.fileobj = fileobj
  280.         self.bufsize = bufsize
  281.         self.buf = ''
  282.         self.pos = 0x0L
  283.         self.closed = False
  284.         if comptype == 'gz':
  285.             
  286.             try:
  287.                 import zlib as zlib
  288.             except ImportError:
  289.                 raise CompressionError('zlib module is not available')
  290.  
  291.             self.zlib = zlib
  292.             self.crc = zlib.crc32('')
  293.             if mode == 'r':
  294.                 self._init_read_gz()
  295.             else:
  296.                 self._init_write_gz()
  297.         
  298.         if comptype == 'bz2':
  299.             
  300.             try:
  301.                 import bz2
  302.             except ImportError:
  303.                 raise CompressionError('bz2 module is not available')
  304.  
  305.             if mode == 'r':
  306.                 self.dbuf = ''
  307.                 self.cmp = bz2.BZ2Decompressor()
  308.             else:
  309.                 self.cmp = bz2.BZ2Compressor()
  310.         
  311.  
  312.     
  313.     def __del__(self):
  314.         if hasattr(self, 'closed') and not (self.closed):
  315.             self.close()
  316.         
  317.  
  318.     
  319.     def _init_write_gz(self):
  320.         '''Initialize for writing with gzip compression.
  321.         '''
  322.         self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, -(self.zlib.MAX_WBITS), self.zlib.DEF_MEM_LEVEL, 0)
  323.         timestamp = struct.pack('<L', long(time.time()))
  324.         self._Stream__write('\x1f\x8b\x08\x08%s\x02\xff' % timestamp)
  325.         if self.name.endswith('.gz'):
  326.             self.name = self.name[:-3]
  327.         
  328.         self._Stream__write(self.name + NUL)
  329.  
  330.     
  331.     def write(self, s):
  332.         '''Write string s to the stream.
  333.         '''
  334.         if self.comptype == 'gz':
  335.             self.crc = self.zlib.crc32(s, self.crc)
  336.         
  337.         self.pos += len(s)
  338.         if self.comptype != 'tar':
  339.             s = self.cmp.compress(s)
  340.         
  341.         self._Stream__write(s)
  342.  
  343.     
  344.     def _Stream__write(self, s):
  345.         '''Write string s to the stream if a whole new block
  346.            is ready to be written.
  347.         '''
  348.         self.buf += s
  349.         while len(self.buf) > self.bufsize:
  350.             self.fileobj.write(self.buf[:self.bufsize])
  351.             self.buf = self.buf[self.bufsize:]
  352.             continue
  353.             self
  354.  
  355.     
  356.     def close(self):
  357.         '''Close the _Stream object. No operation should be
  358.            done on it afterwards.
  359.         '''
  360.         if self.closed:
  361.             return None
  362.         
  363.         if self.mode == 'w' and self.comptype != 'tar':
  364.             self.buf += self.cmp.flush()
  365.         
  366.         if self.mode == 'w' and self.buf:
  367.             self.fileobj.write(self.buf)
  368.             self.buf = ''
  369.             if self.comptype == 'gz':
  370.                 self.fileobj.write(struct.pack('<L', self.crc & 0xFFFFFFFFL))
  371.                 self.fileobj.write(struct.pack('<L', self.pos & 0xFFFFFFFFL))
  372.             
  373.         
  374.         if not self._extfileobj:
  375.             self.fileobj.close()
  376.         
  377.         self.closed = True
  378.  
  379.     
  380.     def _init_read_gz(self):
  381.         '''Initialize for reading a gzip compressed fileobj.
  382.         '''
  383.         self.cmp = self.zlib.decompressobj(-(self.zlib.MAX_WBITS))
  384.         self.dbuf = ''
  385.         if self._Stream__read(2) != '\x1f\x8b':
  386.             raise ReadError('not a gzip file')
  387.         
  388.         if self._Stream__read(1) != '\x08':
  389.             raise CompressionError('unsupported compression method')
  390.         
  391.         flag = ord(self._Stream__read(1))
  392.         self._Stream__read(6)
  393.         if flag & 4:
  394.             xlen = ord(self._Stream__read(1)) + 256 * ord(self._Stream__read(1))
  395.             self.read(xlen)
  396.         
  397.         if flag & 8:
  398.             while True:
  399.                 s = self._Stream__read(1)
  400.                 if not s or s == NUL:
  401.                     break
  402.                     continue
  403.         
  404.         if flag & 16:
  405.             while True:
  406.                 s = self._Stream__read(1)
  407.                 if not s or s == NUL:
  408.                     break
  409.                     continue
  410.         
  411.         if flag & 2:
  412.             self._Stream__read(2)
  413.         
  414.  
  415.     
  416.     def tell(self):
  417.         """Return the stream's file pointer position.
  418.         """
  419.         return self.pos
  420.  
  421.     
  422.     def seek(self, pos = 0):
  423.         """Set the stream's file pointer to pos. Negative seeking
  424.            is forbidden.
  425.         """
  426.         if pos - self.pos >= 0:
  427.             (blocks, remainder) = divmod(pos - self.pos, self.bufsize)
  428.             for i in xrange(blocks):
  429.                 self.read(self.bufsize)
  430.             
  431.             self.read(remainder)
  432.         else:
  433.             raise StreamError('seeking backwards is not allowed')
  434.         return self.pos
  435.  
  436.     
  437.     def read(self, size = None):
  438.         '''Return the next size number of bytes from the stream.
  439.            If size is not defined, return all bytes of the stream
  440.            up to EOF.
  441.         '''
  442.         if size is None:
  443.             t = []
  444.             while True:
  445.                 buf = self._read(self.bufsize)
  446.                 if not buf:
  447.                     break
  448.                 
  449.                 t.append(buf)
  450.             buf = ''.join(t)
  451.         else:
  452.             buf = self._read(size)
  453.         self.pos += len(buf)
  454.         return buf
  455.  
  456.     
  457.     def _read(self, size):
  458.         '''Return size bytes from the stream.
  459.         '''
  460.         if self.comptype == 'tar':
  461.             return self._Stream__read(size)
  462.         
  463.         c = len(self.dbuf)
  464.         t = [
  465.             self.dbuf]
  466.         while c < size:
  467.             buf = self._Stream__read(self.bufsize)
  468.             if not buf:
  469.                 break
  470.             
  471.             buf = self.cmp.decompress(buf)
  472.             t.append(buf)
  473.             c += len(buf)
  474.         t = ''.join(t)
  475.         self.dbuf = t[size:]
  476.         return t[:size]
  477.  
  478.     
  479.     def _Stream__read(self, size):
  480.         '''Return size bytes from stream. If internal buffer is empty,
  481.            read another block from the stream.
  482.         '''
  483.         c = len(self.buf)
  484.         t = [
  485.             self.buf]
  486.         while c < size:
  487.             buf = self.fileobj.read(self.bufsize)
  488.             if not buf:
  489.                 break
  490.             
  491.             t.append(buf)
  492.             c += len(buf)
  493.         t = ''.join(t)
  494.         self.buf = t[size:]
  495.         return t[:size]
  496.  
  497.  
  498.  
  499. class _StreamProxy(object):
  500.     """Small proxy class that enables transparent compression
  501.        detection for the Stream interface (mode 'r|*').
  502.     """
  503.     
  504.     def __init__(self, fileobj):
  505.         self.fileobj = fileobj
  506.         self.buf = self.fileobj.read(BLOCKSIZE)
  507.  
  508.     
  509.     def read(self, size):
  510.         self.read = self.fileobj.read
  511.         return self.buf
  512.  
  513.     
  514.     def getcomptype(self):
  515.         if self.buf.startswith('\x1f\x8b\x08'):
  516.             return 'gz'
  517.         
  518.         if self.buf.startswith('BZh91'):
  519.             return 'bz2'
  520.         
  521.         return 'tar'
  522.  
  523.     
  524.     def close(self):
  525.         self.fileobj.close()
  526.  
  527.  
  528.  
  529. class _BZ2Proxy(object):
  530.     '''Small proxy class that enables external file object
  531.        support for "r:bz2" and "w:bz2" modes. This is actually
  532.        a workaround for a limitation in bz2 module\'s BZ2File
  533.        class which (unlike gzip.GzipFile) has no support for
  534.        a file object argument.
  535.     '''
  536.     blocksize = 16384
  537.     
  538.     def __init__(self, fileobj, mode):
  539.         self.fileobj = fileobj
  540.         self.mode = mode
  541.         self.init()
  542.  
  543.     
  544.     def init(self):
  545.         import bz2
  546.         self.pos = 0
  547.         if self.mode == 'r':
  548.             self.bz2obj = bz2.BZ2Decompressor()
  549.             self.fileobj.seek(0)
  550.             self.buf = ''
  551.         else:
  552.             self.bz2obj = bz2.BZ2Compressor()
  553.  
  554.     
  555.     def read(self, size):
  556.         b = [
  557.             self.buf]
  558.         x = len(self.buf)
  559.         while x < size:
  560.             
  561.             try:
  562.                 raw = self.fileobj.read(self.blocksize)
  563.                 data = self.bz2obj.decompress(raw)
  564.                 b.append(data)
  565.             except EOFError:
  566.                 break
  567.  
  568.             x += len(data)
  569.         self.buf = ''.join(b)
  570.         buf = self.buf[:size]
  571.         self.buf = self.buf[size:]
  572.         self.pos += len(buf)
  573.         return buf
  574.  
  575.     
  576.     def seek(self, pos):
  577.         if pos < self.pos:
  578.             self.init()
  579.         
  580.         self.read(pos - self.pos)
  581.  
  582.     
  583.     def tell(self):
  584.         return self.pos
  585.  
  586.     
  587.     def write(self, data):
  588.         self.pos += len(data)
  589.         raw = self.bz2obj.compress(data)
  590.         self.fileobj.write(raw)
  591.  
  592.     
  593.     def close(self):
  594.         if self.mode == 'w':
  595.             raw = self.bz2obj.flush()
  596.             self.fileobj.write(raw)
  597.         
  598.         self.fileobj.close()
  599.  
  600.  
  601.  
  602. class _FileInFile(object):
  603.     '''A thin wrapper around an existing file object that
  604.        provides a part of its data as an individual file
  605.        object.
  606.     '''
  607.     
  608.     def __init__(self, fileobj, offset, size, sparse = None):
  609.         self.fileobj = fileobj
  610.         self.offset = offset
  611.         self.size = size
  612.         self.sparse = sparse
  613.         self.position = 0
  614.  
  615.     
  616.     def tell(self):
  617.         '''Return the current file position.
  618.         '''
  619.         return self.position
  620.  
  621.     
  622.     def seek(self, position):
  623.         '''Seek to a position in the file.
  624.         '''
  625.         self.position = position
  626.  
  627.     
  628.     def read(self, size = None):
  629.         '''Read data from the file.
  630.         '''
  631.         if size is None:
  632.             size = self.size - self.position
  633.         else:
  634.             size = min(size, self.size - self.position)
  635.         if self.sparse is None:
  636.             return self.readnormal(size)
  637.         else:
  638.             return self.readsparse(size)
  639.  
  640.     
  641.     def readnormal(self, size):
  642.         '''Read operation for regular files.
  643.         '''
  644.         self.fileobj.seek(self.offset + self.position)
  645.         self.position += size
  646.         return self.fileobj.read(size)
  647.  
  648.     
  649.     def readsparse(self, size):
  650.         '''Read operation for sparse files.
  651.         '''
  652.         data = []
  653.         while size > 0:
  654.             buf = self.readsparsesection(size)
  655.             if not buf:
  656.                 break
  657.             
  658.             size -= len(buf)
  659.             data.append(buf)
  660.         return ''.join(data)
  661.  
  662.     
  663.     def readsparsesection(self, size):
  664.         '''Read a single section of a sparse file.
  665.         '''
  666.         section = self.sparse.find(self.position)
  667.         if section is None:
  668.             return ''
  669.         
  670.         size = min(size, section.offset + section.size - self.position)
  671.  
  672.  
  673.  
  674. class ExFileObject(object):
  675.     '''File-like object for reading an archive member.
  676.        Is returned by TarFile.extractfile().
  677.     '''
  678.     blocksize = 1024
  679.     
  680.     def __init__(self, tarfile, tarinfo):
  681.         self.fileobj = _FileInFile(tarfile.fileobj, tarinfo.offset_data, tarinfo.size, getattr(tarinfo, 'sparse', None))
  682.         self.name = tarinfo.name
  683.         self.mode = 'r'
  684.         self.closed = False
  685.         self.size = tarinfo.size
  686.         self.position = 0
  687.         self.buffer = ''
  688.  
  689.     
  690.     def read(self, size = None):
  691.         '''Read at most size bytes from the file. If size is not
  692.            present or None, read all data until EOF is reached.
  693.         '''
  694.         if self.closed:
  695.             raise ValueError('I/O operation on closed file')
  696.         
  697.         buf = ''
  698.         if self.buffer:
  699.             if size is None:
  700.                 buf = self.buffer
  701.                 self.buffer = ''
  702.             else:
  703.                 buf = self.buffer[:size]
  704.                 self.buffer = self.buffer[size:]
  705.         
  706.         if size is None:
  707.             buf += self.fileobj.read()
  708.         else:
  709.             buf += self.fileobj.read(size - len(buf))
  710.         self.position += len(buf)
  711.         return buf
  712.  
  713.     
  714.     def readline(self, size = -1):
  715.         '''Read one entire line from the file. If size is present
  716.            and non-negative, return a string with at most that
  717.            size, which may be an incomplete line.
  718.         '''
  719.         if self.closed:
  720.             raise ValueError('I/O operation on closed file')
  721.         
  722.         if '\n' in self.buffer:
  723.             pos = self.buffer.find('\n') + 1
  724.         else:
  725.             buffers = [
  726.                 self.buffer]
  727.             while True:
  728.                 buf = self.fileobj.read(self.blocksize)
  729.                 buffers.append(buf)
  730.                 if not buf or '\n' in buf:
  731.                     self.buffer = ''.join(buffers)
  732.                     pos = self.buffer.find('\n') + 1
  733.                     if pos == 0:
  734.                         pos = len(self.buffer)
  735.                     
  736.                     break
  737.                     continue
  738.         if size != -1:
  739.             pos = min(size, pos)
  740.         
  741.         buf = self.buffer[:pos]
  742.         self.buffer = self.buffer[pos:]
  743.         self.position += len(buf)
  744.         return buf
  745.  
  746.     
  747.     def readlines(self):
  748.         '''Return a list with all remaining lines.
  749.         '''
  750.         result = []
  751.         while True:
  752.             line = self.readline()
  753.             if not line:
  754.                 break
  755.             
  756.             result.append(line)
  757.         return result
  758.  
  759.     
  760.     def tell(self):
  761.         '''Return the current file position.
  762.         '''
  763.         if self.closed:
  764.             raise ValueError('I/O operation on closed file')
  765.         
  766.         return self.position
  767.  
  768.     
  769.     def seek(self, pos, whence = os.SEEK_SET):
  770.         '''Seek to a position in the file.
  771.         '''
  772.         if self.closed:
  773.             raise ValueError('I/O operation on closed file')
  774.         
  775.         if whence == os.SEEK_SET:
  776.             self.position = min(max(pos, 0), self.size)
  777.         elif whence == os.SEEK_CUR:
  778.             if pos < 0:
  779.                 self.position = max(self.position + pos, 0)
  780.             else:
  781.                 self.position = min(self.position + pos, self.size)
  782.         elif whence == os.SEEK_END:
  783.             self.position = max(min(self.size + pos, self.size), 0)
  784.         else:
  785.             raise ValueError('Invalid argument')
  786.         self.buffer = ''
  787.         self.fileobj.seek(self.position)
  788.  
  789.     
  790.     def close(self):
  791.         '''Close the file object.
  792.         '''
  793.         self.closed = True
  794.  
  795.     
  796.     def __iter__(self):
  797.         """Get an iterator over the file's lines.
  798.         """
  799.         while True:
  800.             line = self.readline()
  801.             if not line:
  802.                 break
  803.             
  804.             yield line
  805.  
  806.  
  807.  
  808. class TarInfo(object):
  809.     '''Informational class which holds the details about an
  810.        archive member given by a tar header block.
  811.        TarInfo objects are returned by TarFile.getmember(),
  812.        TarFile.getmembers() and TarFile.gettarinfo() and are
  813.        usually created internally.
  814.     '''
  815.     
  816.     def __init__(self, name = ''):
  817.         '''Construct a TarInfo object. name is the optional name
  818.            of the member.
  819.         '''
  820.         self.name = name
  821.         self.mode = 438
  822.         self.uid = 0
  823.         self.gid = 0
  824.         self.size = 0
  825.         self.mtime = 0
  826.         self.chksum = 0
  827.         self.type = REGTYPE
  828.         self.linkname = ''
  829.         self.uname = 'user'
  830.         self.gname = 'group'
  831.         self.devmajor = 0
  832.         self.devminor = 0
  833.         self.offset = 0
  834.         self.offset_data = 0
  835.  
  836.     
  837.     def __repr__(self):
  838.         return '<%s %r at %#x>' % (self.__class__.__name__, self.name, id(self))
  839.  
  840.     
  841.     def frombuf(cls, buf):
  842.         '''Construct a TarInfo object from a 512 byte string buffer.
  843.         '''
  844.         if len(buf) != BLOCKSIZE:
  845.             raise ValueError('truncated header')
  846.         
  847.         if buf.count(NUL) == BLOCKSIZE:
  848.             raise ValueError('empty header')
  849.         
  850.         tarinfo = cls()
  851.         tarinfo.buf = buf
  852.         tarinfo.name = nts(buf[0:100])
  853.         tarinfo.mode = nti(buf[100:108])
  854.         tarinfo.uid = nti(buf[108:116])
  855.         tarinfo.gid = nti(buf[116:124])
  856.         tarinfo.size = nti(buf[124:136])
  857.         tarinfo.mtime = nti(buf[136:148])
  858.         tarinfo.chksum = nti(buf[148:156])
  859.         tarinfo.type = buf[156:157]
  860.         tarinfo.linkname = nts(buf[157:257])
  861.         tarinfo.uname = nts(buf[265:297])
  862.         tarinfo.gname = nts(buf[297:329])
  863.         tarinfo.devmajor = nti(buf[329:337])
  864.         tarinfo.devminor = nti(buf[337:345])
  865.         prefix = nts(buf[345:500])
  866.         if prefix and not tarinfo.issparse():
  867.             tarinfo.name = prefix + '/' + tarinfo.name
  868.         
  869.         if tarinfo.chksum not in calc_chksums(buf):
  870.             raise ValueError('invalid header')
  871.         
  872.         return tarinfo
  873.  
  874.     frombuf = classmethod(frombuf)
  875.     
  876.     def tobuf(self, posix = False):
  877.         '''Return a tar header as a string of 512 byte blocks.
  878.         '''
  879.         buf = ''
  880.         type = self.type
  881.         prefix = ''
  882.         if self.name.endswith('/'):
  883.             type = DIRTYPE
  884.         
  885.         if type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK):
  886.             name = self.name
  887.         else:
  888.             name = normpath(self.name)
  889.         if type == DIRTYPE:
  890.             name += '/'
  891.         
  892.         linkname = self.linkname
  893.         if linkname:
  894.             linkname = normpath(linkname)
  895.         
  896.         if posix:
  897.             if self.size > MAXSIZE_MEMBER:
  898.                 raise ValueError('file is too large (>= 8 GB)')
  899.             
  900.             if len(self.linkname) > LENGTH_LINK:
  901.                 raise ValueError('linkname is too long (>%d)' % LENGTH_LINK)
  902.             
  903.             if len(name) > LENGTH_NAME:
  904.                 prefix = name[:LENGTH_PREFIX + 1]
  905.                 while prefix and prefix[-1] != '/':
  906.                     prefix = prefix[:-1]
  907.                 name = name[len(prefix):]
  908.                 prefix = prefix[:-1]
  909.                 if not prefix or len(name) > LENGTH_NAME:
  910.                     raise ValueError('name is too long')
  911.                 
  912.             
  913.         elif len(self.linkname) > LENGTH_LINK:
  914.             buf += self._create_gnulong(self.linkname, GNUTYPE_LONGLINK)
  915.         
  916.         if len(name) > LENGTH_NAME:
  917.             buf += self._create_gnulong(name, GNUTYPE_LONGNAME)
  918.         
  919.         parts = [
  920.             stn(name, 100),
  921.             itn(self.mode & 4095, 8, posix),
  922.             itn(self.uid, 8, posix),
  923.             itn(self.gid, 8, posix),
  924.             itn(self.size, 12, posix),
  925.             itn(self.mtime, 12, posix),
  926.             '        ',
  927.             type,
  928.             stn(self.linkname, 100),
  929.             stn(MAGIC, 6),
  930.             stn(VERSION, 2),
  931.             stn(self.uname, 32),
  932.             stn(self.gname, 32),
  933.             itn(self.devmajor, 8, posix),
  934.             itn(self.devminor, 8, posix),
  935.             stn(prefix, 155)]
  936.         buf += ''.join(parts).ljust(BLOCKSIZE, NUL)
  937.         chksum = calc_chksums(buf[-BLOCKSIZE:])[0]
  938.         buf = buf[:-364] + '%06o\x00' % chksum + buf[-357:]
  939.         self.buf = buf
  940.         return buf
  941.  
  942.     
  943.     def _create_gnulong(self, name, type):
  944.         '''Create a GNU longname/longlink header from name.
  945.            It consists of an extended tar header, with the length
  946.            of the longname as size, followed by data blocks,
  947.            which contain the longname as a null terminated string.
  948.         '''
  949.         name += NUL
  950.         tarinfo = self.__class__()
  951.         tarinfo.name = '././@LongLink'
  952.         tarinfo.type = type
  953.         tarinfo.mode = 0
  954.         tarinfo.size = len(name)
  955.         buf = tarinfo.tobuf()
  956.         buf += name
  957.         (blocks, remainder) = divmod(len(name), BLOCKSIZE)
  958.         if remainder > 0:
  959.             buf += (BLOCKSIZE - remainder) * NUL
  960.         
  961.         return buf
  962.  
  963.     
  964.     def isreg(self):
  965.         return self.type in REGULAR_TYPES
  966.  
  967.     
  968.     def isfile(self):
  969.         return self.isreg()
  970.  
  971.     
  972.     def isdir(self):
  973.         return self.type == DIRTYPE
  974.  
  975.     
  976.     def issym(self):
  977.         return self.type == SYMTYPE
  978.  
  979.     
  980.     def islnk(self):
  981.         return self.type == LNKTYPE
  982.  
  983.     
  984.     def ischr(self):
  985.         return self.type == CHRTYPE
  986.  
  987.     
  988.     def isblk(self):
  989.         return self.type == BLKTYPE
  990.  
  991.     
  992.     def isfifo(self):
  993.         return self.type == FIFOTYPE
  994.  
  995.     
  996.     def issparse(self):
  997.         return self.type == GNUTYPE_SPARSE
  998.  
  999.     
  1000.     def isdev(self):
  1001.         return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE)
  1002.  
  1003.  
  1004.  
  1005. class TarFile(object):
  1006.     '''The TarFile Class provides an interface to tar archives.
  1007.     '''
  1008.     debug = 0
  1009.     dereference = False
  1010.     ignore_zeros = False
  1011.     errorlevel = 0
  1012.     posix = False
  1013.     fileobject = ExFileObject
  1014.     
  1015.     def __init__(self, name = None, mode = 'r', fileobj = None):
  1016.         """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
  1017.            read from an existing archive, 'a' to append data to an existing
  1018.            file or 'w' to create a new file overwriting an existing one. `mode'
  1019.            defaults to 'r'.
  1020.            If `fileobj' is given, it is used for reading or writing data. If it
  1021.            can be determined, `mode' is overridden by `fileobj's mode.
  1022.            `fileobj' is not closed, when TarFile is closed.
  1023.         """
  1024.         if len(mode) > 1 or mode not in 'raw':
  1025.             raise ValueError("mode must be 'r', 'a' or 'w'")
  1026.         
  1027.         self._mode = mode
  1028.         self.mode = {
  1029.             'r': 'rb',
  1030.             'a': 'r+b',
  1031.             'w': 'wb' }[mode]
  1032.         if not fileobj:
  1033.             fileobj = file(name, self.mode)
  1034.             self._extfileobj = False
  1035.         elif name is None and hasattr(fileobj, 'name'):
  1036.             name = fileobj.name
  1037.         
  1038.         if hasattr(fileobj, 'mode'):
  1039.             self.mode = fileobj.mode
  1040.         
  1041.         self._extfileobj = True
  1042.         self.name = None if name else None
  1043.         self.fileobj = fileobj
  1044.         self.closed = False
  1045.         self.members = []
  1046.         self._loaded = False
  1047.         self.offset = self.fileobj.tell()
  1048.         self.inodes = { }
  1049.         if self._mode == 'r':
  1050.             self.firstmember = None
  1051.             self.firstmember = self.next()
  1052.         
  1053.         if self._mode == 'a':
  1054.             self.firstmember = None
  1055.             while True:
  1056.                 
  1057.                 try:
  1058.                     tarinfo = self.next()
  1059.                 except ReadError:
  1060.                     self.fileobj.seek(0)
  1061.                     break
  1062.  
  1063.                 if tarinfo is None:
  1064.                     self.fileobj.seek(-BLOCKSIZE, 1)
  1065.                     break
  1066.                     continue
  1067.         
  1068.         if self._mode in 'aw':
  1069.             self._loaded = True
  1070.         
  1071.  
  1072.     
  1073.     def open(cls, name = None, mode = 'r', fileobj = None, bufsize = 10240):
  1074.         """Open a tar archive for reading, writing or appending. Return
  1075.            an appropriate TarFile class.
  1076.  
  1077.            mode:
  1078.            'r' or 'r:*' open for reading with transparent compression
  1079.            'r:'         open for reading exclusively uncompressed
  1080.            'r:gz'       open for reading with gzip compression
  1081.            'r:bz2'      open for reading with bzip2 compression
  1082.            'a' or 'a:'  open for appending
  1083.            'w' or 'w:'  open for writing without compression
  1084.            'w:gz'       open for writing with gzip compression
  1085.            'w:bz2'      open for writing with bzip2 compression
  1086.  
  1087.            'r|*'        open a stream of tar blocks with transparent compression
  1088.            'r|'         open an uncompressed stream of tar blocks for reading
  1089.            'r|gz'       open a gzip compressed stream of tar blocks
  1090.            'r|bz2'      open a bzip2 compressed stream of tar blocks
  1091.            'w|'         open an uncompressed stream for writing
  1092.            'w|gz'       open a gzip compressed stream for writing
  1093.            'w|bz2'      open a bzip2 compressed stream for writing
  1094.         """
  1095.         if not name and not fileobj:
  1096.             raise ValueError('nothing to open')
  1097.         
  1098.         if mode in ('r', 'r:*'):
  1099.             for comptype in cls.OPEN_METH:
  1100.                 func = getattr(cls, cls.OPEN_METH[comptype])
  1101.                 if fileobj is not None:
  1102.                     saved_pos = fileobj.tell()
  1103.                 
  1104.                 
  1105.                 try:
  1106.                     return func(name, 'r', fileobj)
  1107.                 continue
  1108.                 except (ReadError, CompressionError):
  1109.                     if fileobj is not None:
  1110.                         fileobj.seek(saved_pos)
  1111.                         continue
  1112.                     continue
  1113.                     continue
  1114.                 
  1115.  
  1116.             
  1117.             raise ReadError('file could not be opened successfully')
  1118.         elif ':' in mode:
  1119.             (filemode, comptype) = mode.split(':', 1)
  1120.             if not filemode:
  1121.                 pass
  1122.             filemode = 'r'
  1123.             if not comptype:
  1124.                 pass
  1125.             comptype = 'tar'
  1126.             if comptype in cls.OPEN_METH:
  1127.                 func = getattr(cls, cls.OPEN_METH[comptype])
  1128.             else:
  1129.                 raise CompressionError('unknown compression type %r' % comptype)
  1130.             return func(name, filemode, fileobj)
  1131.         elif '|' in mode:
  1132.             (filemode, comptype) = mode.split('|', 1)
  1133.             if not filemode:
  1134.                 pass
  1135.             filemode = 'r'
  1136.             if not comptype:
  1137.                 pass
  1138.             comptype = 'tar'
  1139.             if filemode not in 'rw':
  1140.                 raise ValueError("mode must be 'r' or 'w'")
  1141.             
  1142.             t = cls(name, filemode, _Stream(name, filemode, comptype, fileobj, bufsize))
  1143.             t._extfileobj = False
  1144.             return t
  1145.         elif mode in 'aw':
  1146.             return cls.taropen(name, mode, fileobj)
  1147.         
  1148.         raise ValueError('undiscernible mode')
  1149.  
  1150.     open = classmethod(open)
  1151.     
  1152.     def taropen(cls, name, mode = 'r', fileobj = None):
  1153.         '''Open uncompressed tar archive name for reading or writing.
  1154.         '''
  1155.         if len(mode) > 1 or mode not in 'raw':
  1156.             raise ValueError("mode must be 'r', 'a' or 'w'")
  1157.         
  1158.         return cls(name, mode, fileobj)
  1159.  
  1160.     taropen = classmethod(taropen)
  1161.     
  1162.     def gzopen(cls, name, mode = 'r', fileobj = None, compresslevel = 9):
  1163.         '''Open gzip compressed tar archive name for reading or writing.
  1164.            Appending is not allowed.
  1165.         '''
  1166.         if len(mode) > 1 or mode not in 'rw':
  1167.             raise ValueError("mode must be 'r' or 'w'")
  1168.         
  1169.         
  1170.         try:
  1171.             import gzip as gzip
  1172.             gzip.GzipFile
  1173.         except (ImportError, AttributeError):
  1174.             raise CompressionError('gzip module is not available')
  1175.  
  1176.         if fileobj is None:
  1177.             fileobj = file(name, mode + 'b')
  1178.         
  1179.         
  1180.         try:
  1181.             t = cls.taropen(name, mode, gzip.GzipFile(name, mode, compresslevel, fileobj))
  1182.         except IOError:
  1183.             raise ReadError('not a gzip file')
  1184.  
  1185.         t._extfileobj = False
  1186.         return t
  1187.  
  1188.     gzopen = classmethod(gzopen)
  1189.     
  1190.     def bz2open(cls, name, mode = 'r', fileobj = None, compresslevel = 9):
  1191.         '''Open bzip2 compressed tar archive name for reading or writing.
  1192.            Appending is not allowed.
  1193.         '''
  1194.         if len(mode) > 1 or mode not in 'rw':
  1195.             raise ValueError("mode must be 'r' or 'w'.")
  1196.         
  1197.         
  1198.         try:
  1199.             import bz2
  1200.         except ImportError:
  1201.             raise CompressionError('bz2 module is not available')
  1202.  
  1203.         if fileobj is not None:
  1204.             fileobj = _BZ2Proxy(fileobj, mode)
  1205.         else:
  1206.             fileobj = bz2.BZ2File(name, mode, compresslevel = compresslevel)
  1207.         
  1208.         try:
  1209.             t = cls.taropen(name, mode, fileobj)
  1210.         except IOError:
  1211.             raise ReadError('not a bzip2 file')
  1212.  
  1213.         t._extfileobj = False
  1214.         return t
  1215.  
  1216.     bz2open = classmethod(bz2open)
  1217.     OPEN_METH = {
  1218.         'tar': 'taropen',
  1219.         'gz': 'gzopen',
  1220.         'bz2': 'bz2open' }
  1221.     
  1222.     def close(self):
  1223.         '''Close the TarFile. In write-mode, two finishing zero blocks are
  1224.            appended to the archive.
  1225.         '''
  1226.         if self.closed:
  1227.             return None
  1228.         
  1229.         if self._mode in 'aw':
  1230.             self.fileobj.write(NUL * BLOCKSIZE * 2)
  1231.             self.offset += BLOCKSIZE * 2
  1232.             (blocks, remainder) = divmod(self.offset, RECORDSIZE)
  1233.             if remainder > 0:
  1234.                 self.fileobj.write(NUL * (RECORDSIZE - remainder))
  1235.             
  1236.         
  1237.         if not self._extfileobj:
  1238.             self.fileobj.close()
  1239.         
  1240.         self.closed = True
  1241.  
  1242.     
  1243.     def getmember(self, name):
  1244.         """Return a TarInfo object for member `name'. If `name' can not be
  1245.            found in the archive, KeyError is raised. If a member occurs more
  1246.            than once in the archive, its last occurence is assumed to be the
  1247.            most up-to-date version.
  1248.         """
  1249.         tarinfo = self._getmember(name)
  1250.         if tarinfo is None:
  1251.             raise KeyError('filename %r not found' % name)
  1252.         
  1253.         return tarinfo
  1254.  
  1255.     
  1256.     def getmembers(self):
  1257.         '''Return the members of the archive as a list of TarInfo objects. The
  1258.            list has the same order as the members in the archive.
  1259.         '''
  1260.         self._check()
  1261.         if not self._loaded:
  1262.             self._load()
  1263.         
  1264.         return self.members
  1265.  
  1266.     
  1267.     def getnames(self):
  1268.         '''Return the members of the archive as a list of their names. It has
  1269.            the same order as the list returned by getmembers().
  1270.         '''
  1271.         return [ tarinfo.name for tarinfo in self.getmembers() ]
  1272.  
  1273.     
  1274.     def gettarinfo(self, name = None, arcname = None, fileobj = None):
  1275.         """Create a TarInfo object for either the file `name' or the file
  1276.            object `fileobj' (using os.fstat on its file descriptor). You can
  1277.            modify some of the TarInfo's attributes before you add it using
  1278.            addfile(). If given, `arcname' specifies an alternative name for the
  1279.            file in the archive.
  1280.         """
  1281.         self._check('aw')
  1282.         if fileobj is not None:
  1283.             name = fileobj.name
  1284.         
  1285.         if arcname is None:
  1286.             arcname = name
  1287.         
  1288.         arcname = normpath(arcname)
  1289.         (drv, arcname) = os.path.splitdrive(arcname)
  1290.         while arcname[0:1] == '/':
  1291.             arcname = arcname[1:]
  1292.         tarinfo = TarInfo()
  1293.         if fileobj is None:
  1294.             if hasattr(os, 'lstat') and not (self.dereference):
  1295.                 statres = os.lstat(name)
  1296.             else:
  1297.                 statres = os.stat(name)
  1298.         else:
  1299.             statres = os.fstat(fileobj.fileno())
  1300.         linkname = ''
  1301.         stmd = statres.st_mode
  1302.         if stat.S_ISREG(stmd):
  1303.             inode = (statres.st_ino, statres.st_dev)
  1304.             if not (self.dereference) and statres.st_nlink > 1 and inode in self.inodes:
  1305.                 type = LNKTYPE
  1306.                 linkname = self.inodes[inode]
  1307.             else:
  1308.                 type = REGTYPE
  1309.                 if inode[0]:
  1310.                     self.inodes[inode] = arcname
  1311.                 
  1312.         elif stat.S_ISDIR(stmd):
  1313.             type = DIRTYPE
  1314.             if arcname[-1:] != '/':
  1315.                 arcname += '/'
  1316.             
  1317.         elif stat.S_ISFIFO(stmd):
  1318.             type = FIFOTYPE
  1319.         elif stat.S_ISLNK(stmd):
  1320.             type = SYMTYPE
  1321.             linkname = os.readlink(name)
  1322.         elif stat.S_ISCHR(stmd):
  1323.             type = CHRTYPE
  1324.         elif stat.S_ISBLK(stmd):
  1325.             type = BLKTYPE
  1326.         else:
  1327.             return None
  1328.         tarinfo.name = arcname
  1329.         tarinfo.mode = stmd
  1330.         tarinfo.uid = statres.st_uid
  1331.         tarinfo.gid = statres.st_gid
  1332.         if stat.S_ISREG(stmd):
  1333.             tarinfo.size = statres.st_size
  1334.         else:
  1335.             tarinfo.size = 0x0L
  1336.         tarinfo.mtime = statres.st_mtime
  1337.         tarinfo.type = type
  1338.         tarinfo.linkname = linkname
  1339.         if pwd:
  1340.             
  1341.             try:
  1342.                 tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0]
  1343.             except KeyError:
  1344.                 pass
  1345.             except:
  1346.                 None<EXCEPTION MATCH>KeyError
  1347.             
  1348.  
  1349.         None<EXCEPTION MATCH>KeyError
  1350.         if grp:
  1351.             
  1352.             try:
  1353.                 tarinfo.gname = grp.getgrgid(tarinfo.gid)[0]
  1354.             except KeyError:
  1355.                 pass
  1356.             except:
  1357.                 None<EXCEPTION MATCH>KeyError
  1358.             
  1359.  
  1360.         None<EXCEPTION MATCH>KeyError
  1361.         if type in (CHRTYPE, BLKTYPE):
  1362.             if hasattr(os, 'major') and hasattr(os, 'minor'):
  1363.                 tarinfo.devmajor = os.major(statres.st_rdev)
  1364.                 tarinfo.devminor = os.minor(statres.st_rdev)
  1365.             
  1366.         
  1367.         return tarinfo
  1368.  
  1369.     
  1370.     def list(self, verbose = True):
  1371.         """Print a table of contents to sys.stdout. If `verbose' is False, only
  1372.            the names of the members are printed. If it is True, an `ls -l'-like
  1373.            output is produced.
  1374.         """
  1375.         self._check()
  1376.         for tarinfo in self:
  1377.             if verbose:
  1378.                 print filemode(tarinfo.mode), None % ('%s/%s', tarinfo.uid if not tarinfo.uname else tarinfo.gid),
  1379.                 if tarinfo.ischr() or tarinfo.isblk():
  1380.                     print '%10s' % '%d,%d' % (tarinfo.devmajor, tarinfo.devminor),
  1381.                 else:
  1382.                     print '%10d' % tarinfo.size,
  1383.                 print '%d-%02d-%02d %02d:%02d:%02d' % time.localtime(tarinfo.mtime)[:6],
  1384.             
  1385.             print tarinfo.name,
  1386.             if verbose:
  1387.                 if tarinfo.issym():
  1388.                     print '->', tarinfo.linkname,
  1389.                 
  1390.                 if tarinfo.islnk():
  1391.                     print 'link to', tarinfo.linkname,
  1392.                 
  1393.             
  1394.             print 
  1395.         
  1396.  
  1397.     
  1398.     def add(self, name, arcname = None, recursive = True):
  1399.         """Add the file `name' to the archive. `name' may be any type of file
  1400.            (directory, fifo, symbolic link, etc.). If given, `arcname'
  1401.            specifies an alternative name for the file in the archive.
  1402.            Directories are added recursively by default. This can be avoided by
  1403.            setting `recursive' to False.
  1404.         """
  1405.         self._check('aw')
  1406.         if arcname is None:
  1407.             arcname = name
  1408.         
  1409.         if self.name is not None and os.path.abspath(name) == self.name:
  1410.             self._dbg(2, 'tarfile: Skipped %r' % name)
  1411.             return None
  1412.         
  1413.         if name == '.':
  1414.             if recursive:
  1415.                 if arcname == '.':
  1416.                     arcname = ''
  1417.                 
  1418.                 for f in os.listdir('.'):
  1419.                     self.add(f, os.path.join(arcname, f))
  1420.                 
  1421.             
  1422.             return None
  1423.         
  1424.         self._dbg(1, name)
  1425.         tarinfo = self.gettarinfo(name, arcname)
  1426.         if tarinfo is None:
  1427.             self._dbg(1, 'tarfile: Unsupported type %r' % name)
  1428.             return None
  1429.         
  1430.         if tarinfo.isreg():
  1431.             f = file(name, 'rb')
  1432.             self.addfile(tarinfo, f)
  1433.             f.close()
  1434.         elif tarinfo.isdir():
  1435.             self.addfile(tarinfo)
  1436.             if recursive:
  1437.                 for f in os.listdir(name):
  1438.                     self.add(os.path.join(name, f), os.path.join(arcname, f))
  1439.                 
  1440.             
  1441.         else:
  1442.             self.addfile(tarinfo)
  1443.  
  1444.     
  1445.     def addfile(self, tarinfo, fileobj = None):
  1446.         """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
  1447.            given, tarinfo.size bytes are read from it and added to the archive.
  1448.            You can create TarInfo objects using gettarinfo().
  1449.            On Windows platforms, `fileobj' should always be opened with mode
  1450.            'rb' to avoid irritation about the file size.
  1451.         """
  1452.         self._check('aw')
  1453.         tarinfo = copy.copy(tarinfo)
  1454.         buf = tarinfo.tobuf(self.posix)
  1455.         self.fileobj.write(buf)
  1456.         self.offset += len(buf)
  1457.         if fileobj is not None:
  1458.             copyfileobj(fileobj, self.fileobj, tarinfo.size)
  1459.             (blocks, remainder) = divmod(tarinfo.size, BLOCKSIZE)
  1460.             if remainder > 0:
  1461.                 self.fileobj.write(NUL * (BLOCKSIZE - remainder))
  1462.                 blocks += 1
  1463.             
  1464.             self.offset += blocks * BLOCKSIZE
  1465.         
  1466.         self.members.append(tarinfo)
  1467.  
  1468.     
  1469.     def extractall(self, path = '.', members = None):
  1470.         """Extract all members from the archive to the current working
  1471.            directory and set owner, modification time and permissions on
  1472.            directories afterwards. `path' specifies a different directory
  1473.            to extract to. `members' is optional and must be a subset of the
  1474.            list returned by getmembers().
  1475.         """
  1476.         directories = []
  1477.         if members is None:
  1478.             members = self
  1479.         
  1480.         for tarinfo in members:
  1481.             if tarinfo.isdir():
  1482.                 directories.append(tarinfo)
  1483.                 tarinfo = copy.copy(tarinfo)
  1484.                 tarinfo.mode = 448
  1485.             
  1486.             self.extract(tarinfo, path)
  1487.         
  1488.         directories.sort((lambda a, b: cmp(a.name, b.name)))
  1489.         directories.reverse()
  1490.         for tarinfo in directories:
  1491.             dirpath = os.path.join(path, tarinfo.name)
  1492.             
  1493.             try:
  1494.                 self.chown(tarinfo, dirpath)
  1495.                 self.utime(tarinfo, dirpath)
  1496.                 self.chmod(tarinfo, dirpath)
  1497.             continue
  1498.             except ExtractError:
  1499.                 e = None
  1500.                 if self.errorlevel > 1:
  1501.                     raise 
  1502.                 else:
  1503.                     self._dbg(1, 'tarfile: %s' % e)
  1504.                 self.errorlevel > 1
  1505.             
  1506.  
  1507.         
  1508.  
  1509.     
  1510.     def extract(self, member, path = ''):
  1511.         """Extract a member from the archive to the current working directory,
  1512.            using its full name. Its file information is extracted as accurately
  1513.            as possible. `member' may be a filename or a TarInfo object. You can
  1514.            specify a different directory using `path'.
  1515.         """
  1516.         self._check('r')
  1517.         if isinstance(member, TarInfo):
  1518.             tarinfo = member
  1519.         else:
  1520.             tarinfo = self.getmember(member)
  1521.         if tarinfo.islnk():
  1522.             tarinfo._link_target = os.path.join(path, tarinfo.linkname)
  1523.         
  1524.         
  1525.         try:
  1526.             self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
  1527.         except EnvironmentError:
  1528.             e = None
  1529.             if self.errorlevel > 0:
  1530.                 raise 
  1531.             elif e.filename is None:
  1532.                 self._dbg(1, 'tarfile: %s' % e.strerror)
  1533.             else:
  1534.                 self._dbg(1, 'tarfile: %s %r' % (e.strerror, e.filename))
  1535.         except ExtractError:
  1536.             e = None
  1537.             if self.errorlevel > 1:
  1538.                 raise 
  1539.             else:
  1540.                 self._dbg(1, 'tarfile: %s' % e)
  1541.         except:
  1542.             self.errorlevel > 1
  1543.  
  1544.  
  1545.     
  1546.     def extractfile(self, member):
  1547.         """Extract a member from the archive as a file object. `member' may be
  1548.            a filename or a TarInfo object. If `member' is a regular file, a
  1549.            file-like object is returned. If `member' is a link, a file-like
  1550.            object is constructed from the link's target. If `member' is none of
  1551.            the above, None is returned.
  1552.            The file-like object is read-only and provides the following
  1553.            methods: read(), readline(), readlines(), seek() and tell()
  1554.         """
  1555.         self._check('r')
  1556.         if isinstance(member, TarInfo):
  1557.             tarinfo = member
  1558.         else:
  1559.             tarinfo = self.getmember(member)
  1560.         if tarinfo.isreg():
  1561.             return self.fileobject(self, tarinfo)
  1562.         elif tarinfo.type not in SUPPORTED_TYPES:
  1563.             return self.fileobject(self, tarinfo)
  1564.         elif tarinfo.islnk() or tarinfo.issym():
  1565.             if isinstance(self.fileobj, _Stream):
  1566.                 raise StreamError('cannot extract (sym)link as file object')
  1567.             else:
  1568.                 return self.extractfile(self._getmember(tarinfo.linkname, tarinfo))
  1569.         else:
  1570.             return None
  1571.  
  1572.     
  1573.     def _extract_member(self, tarinfo, targetpath):
  1574.         '''Extract the TarInfo object tarinfo to a physical
  1575.            file called targetpath.
  1576.         '''
  1577.         if targetpath[-1:] == '/':
  1578.             targetpath = targetpath[:-1]
  1579.         
  1580.         targetpath = os.path.normpath(targetpath)
  1581.         upperdirs = os.path.dirname(targetpath)
  1582.         if upperdirs and not os.path.exists(upperdirs):
  1583.             os.makedirs(upperdirs)
  1584.         
  1585.         if tarinfo.islnk() or tarinfo.issym():
  1586.             self._dbg(1, '%s -> %s' % (tarinfo.name, tarinfo.linkname))
  1587.         else:
  1588.             self._dbg(1, tarinfo.name)
  1589.         if tarinfo.isreg():
  1590.             self.makefile(tarinfo, targetpath)
  1591.         elif tarinfo.isdir():
  1592.             self.makedir(tarinfo, targetpath)
  1593.         elif tarinfo.isfifo():
  1594.             self.makefifo(tarinfo, targetpath)
  1595.         elif tarinfo.ischr() or tarinfo.isblk():
  1596.             self.makedev(tarinfo, targetpath)
  1597.         elif tarinfo.islnk() or tarinfo.issym():
  1598.             self.makelink(tarinfo, targetpath)
  1599.         elif tarinfo.type not in SUPPORTED_TYPES:
  1600.             self.makeunknown(tarinfo, targetpath)
  1601.         else:
  1602.             self.makefile(tarinfo, targetpath)
  1603.         self.chown(tarinfo, targetpath)
  1604.         if not tarinfo.issym():
  1605.             self.chmod(tarinfo, targetpath)
  1606.             self.utime(tarinfo, targetpath)
  1607.         
  1608.  
  1609.     
  1610.     def makedir(self, tarinfo, targetpath):
  1611.         '''Make a directory called targetpath.
  1612.         '''
  1613.         
  1614.         try:
  1615.             os.mkdir(targetpath, 448)
  1616.         except EnvironmentError:
  1617.             e = None
  1618.             if e.errno != errno.EEXIST:
  1619.                 raise 
  1620.             
  1621.         except:
  1622.             e.errno != errno.EEXIST
  1623.  
  1624.  
  1625.     
  1626.     def makefile(self, tarinfo, targetpath):
  1627.         '''Make a file called targetpath.
  1628.         '''
  1629.         source = self.extractfile(tarinfo)
  1630.         target = file(targetpath, 'wb')
  1631.         copyfileobj(source, target)
  1632.         source.close()
  1633.         target.close()
  1634.  
  1635.     
  1636.     def makeunknown(self, tarinfo, targetpath):
  1637.         '''Make a file from a TarInfo object with an unknown type
  1638.            at targetpath.
  1639.         '''
  1640.         self.makefile(tarinfo, targetpath)
  1641.         self._dbg(1, 'tarfile: Unknown file type %r, extracted as regular file.' % tarinfo.type)
  1642.  
  1643.     
  1644.     def makefifo(self, tarinfo, targetpath):
  1645.         '''Make a fifo called targetpath.
  1646.         '''
  1647.         if hasattr(os, 'mkfifo'):
  1648.             os.mkfifo(targetpath)
  1649.         else:
  1650.             raise ExtractError('fifo not supported by system')
  1651.  
  1652.     
  1653.     def makedev(self, tarinfo, targetpath):
  1654.         '''Make a character or block device called targetpath.
  1655.         '''
  1656.         if not hasattr(os, 'mknod') or not hasattr(os, 'makedev'):
  1657.             raise ExtractError('special devices not supported by system')
  1658.         
  1659.         mode = tarinfo.mode
  1660.         if tarinfo.isblk():
  1661.             mode |= stat.S_IFBLK
  1662.         else:
  1663.             mode |= stat.S_IFCHR
  1664.         os.mknod(targetpath, mode, os.makedev(tarinfo.devmajor, tarinfo.devminor))
  1665.  
  1666.     
  1667.     def makelink(self, tarinfo, targetpath):
  1668.         '''Make a (symbolic) link called targetpath. If it cannot be created
  1669.           (platform limitation), we try to make a copy of the referenced file
  1670.           instead of a link.
  1671.         '''
  1672.         linkpath = tarinfo.linkname
  1673.         
  1674.         try:
  1675.             if tarinfo.issym():
  1676.                 os.symlink(linkpath, targetpath)
  1677.             else:
  1678.                 os.link(tarinfo._link_target, targetpath)
  1679.         except AttributeError:
  1680.             if tarinfo.issym():
  1681.                 linkpath = os.path.join(os.path.dirname(tarinfo.name), linkpath)
  1682.                 linkpath = normpath(linkpath)
  1683.             
  1684.             
  1685.             try:
  1686.                 self._extract_member(self.getmember(linkpath), targetpath)
  1687.             except (EnvironmentError, KeyError):
  1688.                 e = None
  1689.                 linkpath = os.path.normpath(linkpath)
  1690.                 
  1691.                 try:
  1692.                     shutil.copy2(linkpath, targetpath)
  1693.                 except EnvironmentError:
  1694.                     e = None
  1695.                     raise IOError('link could not be created')
  1696.                 except:
  1697.                     None<EXCEPTION MATCH>EnvironmentError
  1698.                 
  1699.  
  1700.                 None<EXCEPTION MATCH>EnvironmentError
  1701.             
  1702.  
  1703.             None<EXCEPTION MATCH>(EnvironmentError, KeyError)
  1704.  
  1705.  
  1706.     
  1707.     def chown(self, tarinfo, targetpath):
  1708.         '''Set owner of targetpath according to tarinfo.
  1709.         '''
  1710.         if pwd and hasattr(os, 'geteuid') and os.geteuid() == 0:
  1711.             
  1712.             try:
  1713.                 g = grp.getgrnam(tarinfo.gname)[2]
  1714.             except KeyError:
  1715.                 
  1716.                 try:
  1717.                     g = grp.getgrgid(tarinfo.gid)[2]
  1718.                 except KeyError:
  1719.                     g = os.getgid()
  1720.                 except:
  1721.                     None<EXCEPTION MATCH>KeyError
  1722.                 
  1723.  
  1724.                 None<EXCEPTION MATCH>KeyError
  1725.  
  1726.             
  1727.             try:
  1728.                 u = pwd.getpwnam(tarinfo.uname)[2]
  1729.             except KeyError:
  1730.                 
  1731.                 try:
  1732.                     u = pwd.getpwuid(tarinfo.uid)[2]
  1733.                 except KeyError:
  1734.                     u = os.getuid()
  1735.                 except:
  1736.                     None<EXCEPTION MATCH>KeyError
  1737.                 
  1738.  
  1739.                 None<EXCEPTION MATCH>KeyError
  1740.  
  1741.             
  1742.             try:
  1743.                 if tarinfo.issym() and hasattr(os, 'lchown'):
  1744.                     os.lchown(targetpath, u, g)
  1745.                 elif sys.platform != 'os2emx':
  1746.                     os.chown(targetpath, u, g)
  1747.             except EnvironmentError:
  1748.                 e = None
  1749.                 raise ExtractError('could not change owner')
  1750.             except:
  1751.                 None<EXCEPTION MATCH>EnvironmentError
  1752.             
  1753.  
  1754.         None<EXCEPTION MATCH>EnvironmentError
  1755.  
  1756.     
  1757.     def chmod(self, tarinfo, targetpath):
  1758.         '''Set file permissions of targetpath according to tarinfo.
  1759.         '''
  1760.         if hasattr(os, 'chmod'):
  1761.             
  1762.             try:
  1763.                 os.chmod(targetpath, tarinfo.mode)
  1764.             except EnvironmentError:
  1765.                 e = None
  1766.                 raise ExtractError('could not change mode')
  1767.             except:
  1768.                 None<EXCEPTION MATCH>EnvironmentError
  1769.             
  1770.  
  1771.         None<EXCEPTION MATCH>EnvironmentError
  1772.  
  1773.     
  1774.     def utime(self, tarinfo, targetpath):
  1775.         '''Set modification time of targetpath according to tarinfo.
  1776.         '''
  1777.         if not hasattr(os, 'utime'):
  1778.             return None
  1779.         
  1780.         if sys.platform == 'win32' and tarinfo.isdir():
  1781.             return None
  1782.         
  1783.         
  1784.         try:
  1785.             os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))
  1786.         except EnvironmentError:
  1787.             e = None
  1788.             raise ExtractError('could not change modification time')
  1789.  
  1790.  
  1791.     
  1792.     def next(self):
  1793.         '''Return the next member of the archive as a TarInfo object, when
  1794.            TarFile is opened for reading. Return None if there is no more
  1795.            available.
  1796.         '''
  1797.         self._check('ra')
  1798.         if self.firstmember is not None:
  1799.             m = self.firstmember
  1800.             self.firstmember = None
  1801.             return m
  1802.         
  1803.         self.fileobj.seek(self.offset)
  1804.         while True:
  1805.             buf = self.fileobj.read(BLOCKSIZE)
  1806.             if not buf:
  1807.                 return None
  1808.             
  1809.             
  1810.             try:
  1811.                 tarinfo = TarInfo.frombuf(buf)
  1812.                 tarinfo.offset = self.offset
  1813.                 self.offset += BLOCKSIZE
  1814.                 tarinfo = self.proc_member(tarinfo)
  1815.             except ValueError:
  1816.                 e = None
  1817.                 if self.ignore_zeros:
  1818.                     self._dbg(2, '0x%X: empty or invalid block: %s' % (self.offset, e))
  1819.                     self.offset += BLOCKSIZE
  1820.                     continue
  1821.                 elif self.offset == 0:
  1822.                     raise ReadError('empty, unreadable or compressed file: %s' % e)
  1823.                 
  1824.                 return None
  1825.  
  1826.             break
  1827.         if tarinfo.isreg() and tarinfo.name.endswith('/'):
  1828.             tarinfo.type = DIRTYPE
  1829.         
  1830.         if tarinfo.isdir() and not tarinfo.name.endswith('/'):
  1831.             tarinfo.name += '/'
  1832.         
  1833.         self.members.append(tarinfo)
  1834.         return tarinfo
  1835.  
  1836.     
  1837.     def proc_member(self, tarinfo):
  1838.         '''Choose the right processing method for tarinfo depending
  1839.            on its type and call it.
  1840.         '''
  1841.         if tarinfo.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK):
  1842.             return self.proc_gnulong(tarinfo)
  1843.         elif tarinfo.type == GNUTYPE_SPARSE:
  1844.             return self.proc_sparse(tarinfo)
  1845.         else:
  1846.             return self.proc_builtin(tarinfo)
  1847.  
  1848.     
  1849.     def proc_builtin(self, tarinfo):
  1850.         '''Process a builtin type member or an unknown member
  1851.            which will be treated as a regular file.
  1852.         '''
  1853.         tarinfo.offset_data = self.offset
  1854.         if tarinfo.isreg() or tarinfo.type not in SUPPORTED_TYPES:
  1855.             self.offset += self._block(tarinfo.size)
  1856.         
  1857.         return tarinfo
  1858.  
  1859.     
  1860.     def proc_gnulong(self, tarinfo):
  1861.         '''Process the blocks that hold a GNU longname
  1862.            or longlink member.
  1863.         '''
  1864.         buf = ''
  1865.         count = tarinfo.size
  1866.         while count > 0:
  1867.             block = self.fileobj.read(BLOCKSIZE)
  1868.             buf += block
  1869.             self.offset += BLOCKSIZE
  1870.             count -= BLOCKSIZE
  1871.             continue
  1872.             self
  1873.         b = self.fileobj.read(BLOCKSIZE)
  1874.         t = TarInfo.frombuf(b)
  1875.         t.offset = self.offset
  1876.         self.offset += BLOCKSIZE
  1877.         next = self.proc_member(t)
  1878.         next.offset = tarinfo.offset
  1879.         if tarinfo.type == GNUTYPE_LONGNAME:
  1880.             next.name = nts(buf)
  1881.         elif tarinfo.type == GNUTYPE_LONGLINK:
  1882.             next.linkname = nts(buf)
  1883.         
  1884.         return next
  1885.  
  1886.     
  1887.     def proc_sparse(self, tarinfo):
  1888.         '''Process a GNU sparse header plus extra headers.
  1889.         '''
  1890.         buf = tarinfo.buf
  1891.         sp = _ringbuffer()
  1892.         pos = 386
  1893.         lastpos = 0x0L
  1894.         realpos = 0x0L
  1895.         for i in xrange(4):
  1896.             
  1897.             try:
  1898.                 offset = nti(buf[pos:pos + 12])
  1899.                 numbytes = nti(buf[pos + 12:pos + 24])
  1900.             except ValueError:
  1901.                 break
  1902.  
  1903.             if offset > lastpos:
  1904.                 sp.append(_hole(lastpos, offset - lastpos))
  1905.             
  1906.             sp.append(_data(offset, numbytes, realpos))
  1907.             realpos += numbytes
  1908.             lastpos = offset + numbytes
  1909.             pos += 24
  1910.         
  1911.         isextended = ord(buf[482])
  1912.         origsize = nti(buf[483:495])
  1913.         while isextended == 1:
  1914.             buf = self.fileobj.read(BLOCKSIZE)
  1915.             self.offset += BLOCKSIZE
  1916.             pos = 0
  1917.             for i in xrange(21):
  1918.                 
  1919.                 try:
  1920.                     offset = nti(buf[pos:pos + 12])
  1921.                     numbytes = nti(buf[pos + 12:pos + 24])
  1922.                 except ValueError:
  1923.                     self
  1924.                     self
  1925.                     break
  1926.                 except:
  1927.                     self
  1928.  
  1929.                 if offset > lastpos:
  1930.                     sp.append(_hole(lastpos, offset - lastpos))
  1931.                 
  1932.                 sp.append(_data(offset, numbytes, realpos))
  1933.                 realpos += numbytes
  1934.                 lastpos = offset + numbytes
  1935.                 pos += 24
  1936.             
  1937.             isextended = ord(buf[504])
  1938.         if lastpos < origsize:
  1939.             sp.append(_hole(lastpos, origsize - lastpos))
  1940.         
  1941.         tarinfo.sparse = sp
  1942.         tarinfo.offset_data = self.offset
  1943.         self.offset += self._block(tarinfo.size)
  1944.         tarinfo.size = origsize
  1945.         return tarinfo
  1946.  
  1947.     
  1948.     def _block(self, count):
  1949.         '''Round up a byte count by BLOCKSIZE and return it,
  1950.            e.g. _block(834) => 1024.
  1951.         '''
  1952.         (blocks, remainder) = divmod(count, BLOCKSIZE)
  1953.         if remainder:
  1954.             blocks += 1
  1955.         
  1956.         return blocks * BLOCKSIZE
  1957.  
  1958.     
  1959.     def _getmember(self, name, tarinfo = None):
  1960.         '''Find an archive member by name from bottom to top.
  1961.            If tarinfo is given, it is used as the starting point.
  1962.         '''
  1963.         members = self.getmembers()
  1964.         if tarinfo is None:
  1965.             end = len(members)
  1966.         else:
  1967.             end = members.index(tarinfo)
  1968.         for i in xrange(end - 1, -1, -1):
  1969.             if name == members[i].name:
  1970.                 return members[i]
  1971.                 continue
  1972.         
  1973.  
  1974.     
  1975.     def _load(self):
  1976.         '''Read through the entire archive file and look for readable
  1977.            members.
  1978.         '''
  1979.         while True:
  1980.             tarinfo = self.next()
  1981.             if tarinfo is None:
  1982.                 break
  1983.                 continue
  1984.         self._loaded = True
  1985.  
  1986.     
  1987.     def _check(self, mode = None):
  1988.         """Check if TarFile is still open, and if the operation's mode
  1989.            corresponds to TarFile's mode.
  1990.         """
  1991.         if self.closed:
  1992.             raise IOError('%s is closed' % self.__class__.__name__)
  1993.         
  1994.         if mode is not None and self._mode not in mode:
  1995.             raise IOError('bad operation for mode %r' % self._mode)
  1996.         
  1997.  
  1998.     
  1999.     def __iter__(self):
  2000.         '''Provide an iterator object.
  2001.         '''
  2002.         if self._loaded:
  2003.             return iter(self.members)
  2004.         else:
  2005.             return TarIter(self)
  2006.  
  2007.     
  2008.     def _dbg(self, level, msg):
  2009.         '''Write debugging output to sys.stderr.
  2010.         '''
  2011.         if level <= self.debug:
  2012.             print >>sys.stderr, msg
  2013.         
  2014.  
  2015.  
  2016.  
  2017. class TarIter:
  2018.     '''Iterator Class.
  2019.  
  2020.        for tarinfo in TarFile(...):
  2021.            suite...
  2022.     '''
  2023.     
  2024.     def __init__(self, tarfile):
  2025.         '''Construct a TarIter object.
  2026.         '''
  2027.         self.tarfile = tarfile
  2028.         self.index = 0
  2029.  
  2030.     
  2031.     def __iter__(self):
  2032.         '''Return iterator object.
  2033.         '''
  2034.         return self
  2035.  
  2036.     
  2037.     def next(self):
  2038.         """Return the next item using TarFile's next() method.
  2039.            When all members have been read, set TarFile as _loaded.
  2040.         """
  2041.         if not self.tarfile._loaded:
  2042.             tarinfo = self.tarfile.next()
  2043.             if not tarinfo:
  2044.                 self.tarfile._loaded = True
  2045.                 raise StopIteration
  2046.             
  2047.         else:
  2048.             
  2049.             try:
  2050.                 tarinfo = self.tarfile.members[self.index]
  2051.             except IndexError:
  2052.                 raise StopIteration
  2053.  
  2054.         self.index += 1
  2055.         return tarinfo
  2056.  
  2057.  
  2058.  
  2059. class _section:
  2060.     '''Base class for _data and _hole.
  2061.     '''
  2062.     
  2063.     def __init__(self, offset, size):
  2064.         self.offset = offset
  2065.         self.size = size
  2066.  
  2067.     
  2068.     def __contains__(self, offset):
  2069.         return None if offset <= offset else offset < self.offset + self.size
  2070.  
  2071.  
  2072.  
  2073. class _data(_section):
  2074.     '''Represent a data section in a sparse file.
  2075.     '''
  2076.     
  2077.     def __init__(self, offset, size, realpos):
  2078.         _section.__init__(self, offset, size)
  2079.         self.realpos = realpos
  2080.  
  2081.  
  2082.  
  2083. class _hole(_section):
  2084.     '''Represent a hole section in a sparse file.
  2085.     '''
  2086.     pass
  2087.  
  2088.  
  2089. class _ringbuffer(list):
  2090.     '''Ringbuffer class which increases performance
  2091.        over a regular list.
  2092.     '''
  2093.     
  2094.     def __init__(self):
  2095.         self.idx = 0
  2096.  
  2097.     
  2098.     def find(self, offset):
  2099.         idx = self.idx
  2100.         while True:
  2101.             item = self[idx]
  2102.             if offset in item:
  2103.                 break
  2104.             
  2105.             idx += 1
  2106.             if idx == len(self):
  2107.                 idx = 0
  2108.             
  2109.             if idx == self.idx:
  2110.                 return None
  2111.                 continue
  2112.         self.idx = idx
  2113.         return item
  2114.  
  2115.  
  2116. TAR_PLAIN = 0
  2117. TAR_GZIPPED = 8
  2118.  
  2119. class TarFileCompat:
  2120.     """TarFile class compatible with standard module zipfile's
  2121.        ZipFile class.
  2122.     """
  2123.     
  2124.     def __init__(self, file, mode = 'r', compression = TAR_PLAIN):
  2125.         if compression == TAR_PLAIN:
  2126.             self.tarfile = TarFile.taropen(file, mode)
  2127.         elif compression == TAR_GZIPPED:
  2128.             self.tarfile = TarFile.gzopen(file, mode)
  2129.         else:
  2130.             raise ValueError('unknown compression constant')
  2131.         if mode[0:1] == 'r':
  2132.             members = self.tarfile.getmembers()
  2133.             for m in members:
  2134.                 m.filename = m.name
  2135.                 m.file_size = m.size
  2136.                 m.date_time = time.gmtime(m.mtime)[:6]
  2137.             
  2138.         
  2139.  
  2140.     
  2141.     def namelist(self):
  2142.         return map((lambda m: m.name), self.infolist())
  2143.  
  2144.     
  2145.     def infolist(self):
  2146.         return filter((lambda m: m.type in REGULAR_TYPES), self.tarfile.getmembers())
  2147.  
  2148.     
  2149.     def printdir(self):
  2150.         self.tarfile.list()
  2151.  
  2152.     
  2153.     def testzip(self):
  2154.         pass
  2155.  
  2156.     
  2157.     def getinfo(self, name):
  2158.         return self.tarfile.getmember(name)
  2159.  
  2160.     
  2161.     def read(self, name):
  2162.         return self.tarfile.extractfile(self.tarfile.getmember(name)).read()
  2163.  
  2164.     
  2165.     def write(self, filename, arcname = None, compress_type = None):
  2166.         self.tarfile.add(filename, arcname)
  2167.  
  2168.     
  2169.     def writestr(self, zinfo, bytes):
  2170.         
  2171.         try:
  2172.             StringIO = StringIO
  2173.             import cStringIO
  2174.         except ImportError:
  2175.             StringIO = StringIO
  2176.             import StringIO
  2177.  
  2178.         import calendar as calendar
  2179.         zinfo.name = zinfo.filename
  2180.         zinfo.size = zinfo.file_size
  2181.         zinfo.mtime = calendar.timegm(zinfo.date_time)
  2182.         self.tarfile.addfile(zinfo, StringIO(bytes))
  2183.  
  2184.     
  2185.     def close(self):
  2186.         self.tarfile.close()
  2187.  
  2188.  
  2189.  
  2190. def is_tarfile(name):
  2191.     '''Return True if name points to a tar archive that we
  2192.        are able to handle, else return False.
  2193.     '''
  2194.     
  2195.     try:
  2196.         t = open(name)
  2197.         t.close()
  2198.         return True
  2199.     except TarError:
  2200.         return False
  2201.  
  2202.  
  2203. open = TarFile.open
  2204.